﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Drawing.Imaging;

namespace SearchPicture
{
    public partial class ColectionImages : Form
    {
        public ColectionImages()
        {
            InitializeComponent();
        }

        class anhxam
        {
            public void Gray(Bitmap bmpInput)
            {
                // Lock the bitmap's bits.  
                Rectangle rtg = new Rectangle(0, 0, bmpInput.Width, bmpInput.Height);
                BitmapData bmpData = bmpInput.LockBits(rtg, ImageLockMode.ReadWrite, bmpInput.PixelFormat);

                // Get the address of the first line.
                IntPtr ptr = bmpData.Scan0;

                // Declare an array to hold the bytes of the bitmap.
                // This code is specific to a bitmap with 24 bits per pixels.
                int bytes = bmpInput.Width * bmpInput.Height * 3;
                byte[] rgbValues = new byte[bytes];

                // Copy the RGB values into the array.
                System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);

                // Gray transform 
                int GrayLevel;
                for (int counter = 0; counter < rgbValues.Length; counter += 3)
                {
                    GrayLevel = (rgbValues[counter + 0] + rgbValues[counter + 1] + rgbValues[counter + 2]) / 3;
                    rgbValues[counter] = rgbValues[counter + 1] = rgbValues[counter + 2] = (byte)GrayLevel;
                }

                // Copy the RGB values back to the bitmap
                System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);

                bmpInput.UnlockBits(bmpData);
            }

            public double Mean(byte[] his)
            {
                double kq = 0;
                for (int i = 0; i < 256; i++) kq = kq + i * his[i];
                return kq;
            }
            public double Variance(byte[] his)
            {
                double kq = 0;
                double _Mean = Mean(his);
                for (int i = 0; i < 256; i++) kq = kq + Math.Pow(i - _Mean, 2) * his[i];
                return kq;
            }
            public double Skewness(byte[] his)
            {
                double kq = 0;
                double _Mean = Mean(his);
                double _Variance = Math.Sqrt(Variance(his));
                for (int i = 0; i < 256; i++) kq = kq + Math.Pow(i - _Mean, 3) * his[i];
                return (kq / Math.Pow(_Variance, 3));
            }
            public double Kurtosis(byte[] his)
            {
                double kq = 0;
                double _Mean = Mean(his);
                for (int i = 0; i < 256; i++) kq = kq + Math.Pow(i - _Mean, 4) * his[i];
                return (kq / 4 - 3);
            }
            public double Entropy(byte[] his)
            {
                double kq = 0;
                for (int i = 0; i < 256; i++)
                    if (his[i] != 0) kq = kq - his[i] * Math.Log(his[i], Math.E);
                return (kq);
            }
        }

        private Bitmap ToGray(Bitmap bm)//chuyen sang anh nhi phan
        {
            Bitmap bitmap = new Bitmap(bm);
            try
            {
                int x, y;
                Color c;
                Byte gray;
                for (y = 0; y < bm.Height - 1; y++)
                {
                    for (x = 0; x < bm.Width - 1; x++)
                    {
                        c = bm.GetPixel(x, y);
                        gray = Convert.ToByte(c.R * 0.287 + c.G * 0.599 + c.B * 0.114);
                        bitmap.SetPixel(x, y, Color.FromArgb(gray, gray, gray));
                    }
                }


            }
            catch (Exception ex)
            {
                MessageBox.Show("error:" + ex);
            }
            return bitmap;

        }

        public Boolean collectAttributesImageTexture(Bitmap bm, String fileImage)//save to file
        {

            Bitmap bmG;
            String[] kq = new String[5];

            anhxam anh = new anhxam();//tao mot doi tuong anhxam

            bmG = ToGray(bm);

            //Tinh H[x]
            int x, y;
            byte[] Histo = new byte[256];
            for (y = 0; y < bmG.Height - 1; y++)
            {
                for (x = 0; x < bmG.Width - 1; x++)
                    Histo[bmG.GetPixel(x, y).R] += 1;
            }


            kq[0] = anh.Mean(Histo).ToString();
            kq[1] = anh.Variance(Histo).ToString();
            kq[2] = anh.Skewness(Histo).ToString();
            kq[3] = anh.Kurtosis(Histo).ToString();
            kq[4] = anh.Entropy(Histo).ToString();

            if (!appendToXMLTexture(kq, fileImage))
            {
                MessageBox.Show("Not Saved");
                return false;
            }
            return true;
        }

        private Boolean appendToXMLTexture(Array h, String fileImage)
        {
            //write array to xml file
            try
            {
                XmlDocument data = new XmlDocument();
                data.Load("texture.xml");
                String str = "";
                foreach (String el in h)
                {
                    str = str + el.ToString() + " ";
                }
                XmlNode root = data.DocumentElement;
                XmlNodeList xmlNL = data.GetElementsByTagName("TEXTURE");
                int count = xmlNL.Count;
                //Create a new node.
                XmlElement elem = data.CreateElement("TEXTURE");
                elem.InnerText = str;

                elem.SetAttribute("id", count.ToString());
                elem.SetAttribute("FileName", fileImage);

                //Add the node to the document.
                root.AppendChild(elem);

                data.Save("texture.xml");
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }

        }

        #region append color
        public Boolean collectAttributesImageColor(Image picture1, String fileImage)
        {
            try{

                int[, ,] bin_Color = new int[18, 3, 3];
                int H, S, V;
                int[] BinColor = new int[162];


                Bitmap bmp = new Bitmap(xuLyAnh(picture1));

                for (int i = 0; i < bmp.Width; i++)
                {
                    for (int j = 0; j < bmp.Height; j++)
                    {
                        Color color_Pixel = bmp.GetPixel(i, j);
                        float pixI = color_Pixel.GetBrightness();

                        H = Convert.ToInt32(Math.Round(color_Pixel.GetHue() / 20));
                        S = Convert.ToInt32(Math.Round(color_Pixel.GetSaturation() / 0.3));
                        V = Convert.ToInt32(Math.Round(color_Pixel.GetBrightness() / 0.3));
                        if (S >= 2)
                            S = 2;
                        if (V >= 2)
                            V = 2;
                        if (H >= 17)
                            H = 17;

                        bin_Color[H, S, V] += 1;

                    }
                }
                
                int n = 0;
                for (int i = 0; i < 18; i++)
                {
                    for (int j = 0; j < 3; j++)
                    {
                        for (int k = 0; k < 3; k++)
                        {
                            BinColor[n] = bin_Color[i, j, k];
                            n++;
                        }
                    }
                }

                if (appendToXML(BinColor, fileImage))///save color
                {
                    pro_xuLi.Value = 100;
                    pro_xuLi.Visible = false;
                }
                else
                {
                    MessageBox.Show("Not Saved");
                }
            
            }
            catch{
                return false;
            }
            return true;
        }

        public String searchImage(Image picture1)
        {
            int[, ,] bin_Color = new int[18, 3, 3];
            int H, S, V;
            int[] BinColor = new int[162];


            Bitmap bmp = new Bitmap(xuLyAnh(picture1));

            for (int i = 0; i < bmp.Width; i++)
            {
                for (int j = 0; j < bmp.Height; j++)
                {
                    Color color_Pixel = bmp.GetPixel(i, j);
                    float pixI = color_Pixel.GetBrightness();

                    H = Convert.ToInt32(Math.Round(color_Pixel.GetHue() / 20));
                    S = Convert.ToInt32(Math.Round(color_Pixel.GetSaturation() / 0.3));
                    V = Convert.ToInt32(Math.Round(color_Pixel.GetBrightness() / 0.3));
                    if (S >= 2)
                        S = 2;
                    if (V >= 2)
                        V = 2;
                    if (H >= 17)
                        H = 17;

                    bin_Color[H, S, V] += 1;

                }
            }
            pro_xuLi.Value = 40;
            int n = 0;
            for (int i = 0; i < 18; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    for (int k = 0; k < 3; k++)
                    {
                        BinColor[n] = bin_Color[i, j, k];
                        n++;
                    }
                }
            }

            pro_xuLi.Value = 50;
            String str = "";

            foreach (int i in BinColor)
            {
                str += i.ToString() + " ";
            }
            pro_xuLi.Value = 60;
            return str;
        }

        public bool isIntInArray(int[] strArray, int key)
        {

            if (strArray.Contains(key))
                return true;
            return false;
        }

        public Image xuLyAnh(Image picture1)//tao ra mot anh nhi phan
        {
            Bitmap bmp = new Bitmap(picture1);
            Byte gray;
            for (int i = 0; i < bmp.Width; i++)
            {
                for (int j = 0; j < bmp.Height; j++)
                {
                    Color color_Pixel = bmp.GetPixel(i, j);
                    float pixI = color_Pixel.GetBrightness();
                    if (pixI < 0.3)
                    {
                        bmp.SetPixel(i, j, Color.Black);
                    }

                    float pixS = color_Pixel.GetSaturation();
                    if (pixS < 0.08)
                    {
                        gray = Convert.ToByte(color_Pixel.R * 0.287 + color_Pixel.G * 0.599 + color_Pixel.B * 0.114);
                        bmp.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
                    }
                }
            }
            return bmp;

        }

        public Bitmap resizeImage(Image img, int width, int height)
        {
            Bitmap b = new Bitmap(width, height);
            Graphics g = Graphics.FromImage((Image)b);

            g.DrawImage(img, 0, 0, width, height);
            g.Dispose();

            return b;
        }

        private Boolean appendToXML(Array h, String fileImage)
        {
            //write array to xml file
            try
            {
                XmlDocument data = new XmlDocument();
                data.Load("xml.xml");
                String str = "";
                foreach (int el in h)
                {
                    str = str + el.ToString() + " ";
                }
                XmlNode root = data.DocumentElement;
                XmlNodeList xmlNL = data.GetElementsByTagName("HSI");
                int count = xmlNL.Count;
                //Create a new node.
                XmlElement elem = data.CreateElement("HSI");
                elem.InnerText = str;

                elem.SetAttribute("id", count.ToString());
                elem.SetAttribute("FileName", fileImage);

                //Add the node to the document.
                root.AppendChild(elem);

                data.Save("xml.xml");
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }

        }

        private int accuracyString(String a, String b)//do do chinh xac cua chuoi nhap vao
        {
            String[] A = a.Split(' ');
            String[] B = b.Split(' ');
            int min = 0, max = 0;

            int interrection = 0, tongA = 0, tongB = 0;
            for (int i = 0; i < 162; i++)
            {
                min = int.Parse(A[i]) < int.Parse(B[i]) ? int.Parse(A[i]) : int.Parse(B[i]);
                interrection += min;
                tongA += int.Parse(A[i]);
                tongB += int.Parse(B[i]);
            }
            Double Match;
            max = tongA > tongB ? tongA : tongB;

            Match = 100 * interrection / max;
            Match = Math.Round(Match);
            return (int)Match;

        }
        
        #endregion

        private void btu_colecting_Click(object sender, EventArgs e)
        {
            Bitmap bmp;
            OpenFileDialog openFile = new OpenFileDialog();
            openFile.Filter = "Images (*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*";
            openFile.Title = "Select a nice picture ^^ ";
            openFile.Multiselect = true;
            pro_xuLi.Visible = true;
            if (openFile.ShowDialog() == DialogResult.OK)
            {               
                int count = openFile.FileNames.Count(),i=0;
                foreach (String FileName in openFile.FileNames)
                {
                    i++;
                    pro_xuLi.Value = (i * 100) / count;
                    bmp = new Bitmap(FileName);
                    bmp = resizeImage(bmp, 256, 256);
                    //if (!collectAttributesImageColor(bmp, FileName))
                    //{
                    //    MessageBox.Show("Cap Nhap Loi");
                    //    break;
                    //}
                    if (!collectAttributesImageTexture(bmp, FileName))
                    {
                        MessageBox.Show("Cap Nhap Loi");
                        break;
                    }
                    
                }
                
            }

            pro_xuLi.Value = 100;            
            MessageBox.Show("Cap Nhap thanh cong");
            pro_xuLi.Visible = false;
        }
    }
}
